package spaceCraft;

import Flyer.*;
import GetOffEr.*;
import Lander.*;
import Navigator.*;


/**
 * The <code>SpaceShip</code> represents navigable space ship that can be
 * handled. Handling includes get off, flying and landing which can be performed
 * in different modes. Switching between them was implemented via pattern
 * STRATEGY. The main purpose was to get flexible implementation of handling
 */
public class SpaceShip extends Device {

    private static final int HASH_VALUE_MULTIPLE = 16;
    private Engine engine;
    private GetOffMode getOffMode;
    private FlyMode flyMode;
    private LandMode landMode;
    private Navigable navigationMode;

    /**
     * Constructor set AutoPilot mode for
     * handling functions of space ship as default
     *
     * @param productInfo represents basic information about space ship as a complex device
     */
    public SpaceShip(ProductInfo productInfo, Engine engine) {
        super(productInfo);
        this.engine = engine;
        getOffMode = new GetOffUnderAutoPilot();
        flyMode = new FlyUnderAutoPilot();
        landMode = new LandUnderAutoPilot();
        navigationMode = new NavigationInDewToEarth();
    }

    /**
     * set getOffMode to value defined by parameter <code>getOffMode</code>
     *
     * @param getOffMode mode to which method switches
     */
    public void setGetOffMode(GetOffMode getOffMode) {
        this.getOffMode = getOffMode;
    }

    /**
     * set flyMode to value defined by parameter <code>flyMode</code>
     *
     * @param flyMode mode to which method switches
     */
    public void setFlyMode(FlyMode flyMode) {
        this.flyMode = flyMode;
    }

    /**
     * set landMode to value defined by parameter <code>landMode</code>
     *
     * @param landMode mode to which method switches
     */
    public void setLandMode(LandMode landMode) {
        this.landMode = landMode;
    }

    /**
     * set navigationMode to value defined by parameter <code>mode</code>
     *
     * @param mode mode to which method switches
     */
    public void setNavigationMode(Navigable mode) {
        this.navigationMode = mode;
    }

    /**
     * space ship gets off
     */
    public String getOff() {
        if (getOffMode == null) {
            return null;
        }
        return getOffMode.getOff(engine);
    }

    /**
     * space ship flies
     */
    public String fly() {
        if (flyMode == null) {
            return null;
        }
        return flyMode.fly(engine);
    }

    /**
     * space ship lands
     */
    public String land() {
        if (landMode == null) {
            return null;
        }
        return landMode.land(engine);
    }

    /**
     * space ship gets location
     */
    public String getCurrentLocation() {
        if (navigationMode == null) {
            return null;
        }
        return navigationMode.getCurrentLocation();
    }

    /**
     * installing new engine to space ship
     *
     * @param engine new fresh engine to install
     */
    public void install(Engine engine) {
        this.engine = engine;
    }

    /**
     * Cause some damage to ship engine. Engine <code>inWorkCondition<code>
     * property is set to false
     */
    public boolean breakEngine() {
        if (engine != null) {
            engine.breakDevice();
            return true;
        }
        return false;
    }

    /**
     * Fixing any problem happened with ship engine. Engine <code>inWorkCondition<code>
     * property is set to true
     */
    public boolean fixEngine() {
        if (engine != null) {
            engine.repairDevice();
            return true;
        }
        return false;
    }

    public boolean equals(Object o) {
        return ((o instanceof SpaceShip) &&
                (this.getProductInfo().equals(((SpaceShip) o).getProductInfo())));
    }

    public int hashCode() {
        return getProductInfo().hashCode() ^ HASH_VALUE_MULTIPLE;
    }

    /**
     * Return <code>ProductInfo</code> properties
     */
    public String toString() {
        return getProductInfo();
    }
}
